Skip to content

feat(extract): model Go native channels as gochan Channel topology - #1949

Draft
ilyabrykau-orca wants to merge 1 commit into
DeusData:mainfrom
ilyabrykau-orca:feat/go-native-channels
Draft

feat(extract): model Go native channels as gochan Channel topology#1949
ilyabrykau-orca wants to merge 1 commit into
DeusData:mainfrom
ilyabrykau-orca:feat/go-native-channels

Conversation

@ilyabrykau-orca

@ilyabrykau-orca ilyabrykau-orca commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Part of #1930draft implementation-proposal per the extraction points sketched in the issue body; will mark ready on a maintainer design ack.

What

Go's own concurrency primitives were invisible: the Go channel extractor only classified gorilla/nhooyr WebSocket send/receive, so a channel-plumbed event pipeline (250 make(chan …), ~710 send/receive sites on the measured repo) produced zero Channel nodes and trace_path stopped dead at every send site.

How (v1, extraction-only — the existing materializer does the rest)

create_channel_edges_for_file and its parallel twin already build Channel nodes + EMITS/LISTENS_ON edges from CBMChannel records, so the whole change lives in the Go extractor:

Also fixes a latent gap this exposed: enclosing_function_qn returned a bare name, which never matches any def QN — so every channel edge (the WebSocket ones included) silently degraded to the file node via find_channel_source's fallback. It now returns module_qn.name, fallback preserved.

Tests (reproduce-first — RED with extract_channels.c stashed)

  • extract_go_native_channels: EMIT+LISTEN records, package-qualified names, unary minus is not a receive.
  • pipeline_go_native_channel_topology: one gochan Channel node with "transport":"gochan", EMITS from Produce and LISTENS_ON from Drain across files (RED: cc == 0, expected 1).
  • 643 green across extraction/pipeline/registry; full scripts/test.sh venue leg green; clang-format clean.

Field census

Landed (same-day baseline, repo @ f555e5ce): Channel nodes 2 → 205 (203 gochan); EMITS 1 → 162; LISTENS_ON 2 → 256; 252 distinct source functions. The gap to the raw source counts is exactly the deferred shapes (non-escaping locals, for range ch, go statements). Full table in the census comment below.

#1932 tracks the family. Related: #1114.

@github-actions

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

@ilyabrykau-orca

Copy link
Copy Markdown
Contributor Author

CI retrigger (no-op amend): test-windows-guards — identical SETUP FAIL: ASCII baseline did not index … nodes: None harness-setup signature, tracked in #1952. No semantic changes.

@ilyabrykau-orca
ilyabrykau-orca force-pushed the feat/go-native-channels branch from f962097 to e41c7df Compare August 31, 2026 08:41
@ilyabrykau-orca

Copy link
Copy Markdown
Contributor Author

Field census landed (same-day baseline vs this branch, repo @ f555e5ce):

main #1949
Channel nodes 2 (both websocket) 205 — 203 gochan + the same 2 websocket
EMITS 1 162
LISTENS_ON 2 256
distinct source functions on gochan edges 252

Against the issue's source counts (~210 sends, ~500 receives): 162 sends and 256 receives captured — the gap is exactly the deferred shapes (locals that never escape, for range ch, go-statement plumbing), per the v1 scope statement. The event pipeline's producer/consumer topology is now walkable.

@DeusData DeusData added enhancement New feature or request parsing/quality Graph extraction bugs, false positives, missing edges priority/normal Standard review queue; useful PR with ordinary maintainer urgency. labels Sep 1, 2026
@DeusData

DeusData commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Thank you for documenting the measured Go channel gap, the extraction-only boundary, and the positive and negative tests. Because this draft changes graph identity and cross-file channel topology, we need more time to review the design carefully. Please keep it in draft for now; the contribution queue is quite full, but we will come back with a grounded decision as soon as capacity allows.

Go's own concurrency primitives were invisible: the Go channel
extractor only classified gorilla/nhooyr WebSocket send/receive, so a
channel-plumbed event pipeline (250 make(chan ...), ~710 send/receive
sites on the measured repo) produced zero Channel nodes and trace_path
stopped dead at every send site.

v1, extraction-only - the existing per-file materializer
(create_channel_edges_for_file and its parallel twin) already builds
Channel nodes and EMITS/LISTENS_ON edges from CBMChannel records:

- send_statement (x <- v) -> EMIT, unary <- -> LISTEN. Both are channel
  operations BY GRAMMAR, so no type inference is needed for precision -
  unlike the WebSocket name heuristics. select comm clauses are covered
  for free (they contain the same node kinds).
- Channel identity: the package-qualified tail identifier
  (module_qn + '.' + field/var name), transport "gochan" - distinct
  from "websocket", whose classifier is untouched. Same-package
  cross-file producer/consumer pairs join on one node.
- Deliberately deferred (documented in DeusData#1930): element types on the
  node, go statements (CROSS_ASYNC), and for-range receives - range
  needs the operand's TYPE to know it is a channel, and a name-shape
  guess would be the DeusData#1932 anti-pattern.

Also fixes a latent gap this exposed: enclosing_function_qn returned a
BARE name, which never matches any def QN, so every channel edge (the
WebSocket ones included) silently degraded to the file node through
find_channel_source's fallback. It now returns module_qn.name, with
the file-node fallback preserved for shapes it cannot express.

Reproduce-first (RED with extract_channels.c stashed):
extract_go_native_channels (EMIT+LISTEN records, package-qualified
names, unary minus not mistaken for a receive) and
pipeline_go_native_channel_topology (one gochan Channel node,
EMITS from Produce and LISTENS_ON from Drain across files). 643 green
across extraction/pipeline/registry.

Part of DeusData#1930

Signed-off-by: Ilya Brykau <ilya.brykau@orca.security>
@ilyabrykau-orca

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (staying in draft as asked). Conflicts were test insertion-anchor drift in tests/test_extraction.c and tests/test_pipeline.c — re-anchored; all source auto-merged. Full scripts/test.sh green on this head.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request parsing/quality Graph extraction bugs, false positives, missing edges priority/normal Standard review queue; useful PR with ordinary maintainer urgency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants